package com.conversationboard.controller;

import java.io.IOException;
import java.security.Principal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.lucene.queryParser.ParseException;

import com.conversationboard.config.Configuration;
import com.conversationboard.fulltext.search.Search;
import com.conversationboard.fulltext.search.SortOrder;
import com.conversationboard.fulltext.search.hit.ThreadHit;
import com.conversationboard.model.Board;
import com.conversationboard.model.Boards;
import com.conversationboard.model.User;

/**
 * Copes with adding new questions into the database (threads). Recently
 * expanded to also cope with polls.
 * 
 * @author Keith Watson
 */

@WebServlet(name = "NewQuestionControllerServlet", urlPatterns = "/NewQuestionControllerServlet")
public class NewQuestionControllerServlet extends HttpServlet {

	private static final long serialVersionUID = 3581891372175335303L;


	public NewQuestionControllerServlet() {
		super();
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		response.setCharacterEncoding("UTF-8");
		request.setCharacterEncoding("UTF-8");

		/*
		 * Firstly, search to see if there are any similar threads. If there
		 * are, give the user the option to tag their new thread on to an
		 * existing thread.
		 */

		String questionTitle = (String) request.getParameter("questionTitle").trim();
		String questionText = (String) request.getParameter("questionText");
		int targetBoardId = Integer.parseInt(request.getParameter("boardId"));
		String confirmedString = request.getParameter("confirm");
		String newThreadString = request.getParameter("newthread");
		String adminId = request.getParameter("adminId");
		String sessionKey = request.getParameter("sKey");
		boolean confirmed = (confirmedString != null);
		boolean newThread = (newThreadString != null);
		boolean isPoll = (request.getParameter("pollItems") != null);

		if (questionText != null) {
			questionText = questionText.trim();
		}

		try {

			Principal principal = request.getUserPrincipal();
			User user = null;

			if (principal != null) {
				user = User.get(principal.getName());
			} else {
				user = User.getAnonymousUser();
			}

			Board board = Boards.getBoard(targetBoardId);

			if ((!user.isLoggedIn()) && board.isRequireRegistration()) {
				return;
			}

			/*
			 * If the board is set as unregistered, then perform the security
			 * checks - allow 15 minutes for people to write a new question.
			 */

			if ((!board.isRequireRegistration()) && (!user.isLoggedIn())) {
				if (!SecurityChecks.passes(request, this, 15)) {
					return;
				}
			}

			/*
			 * If we're configured to look for similar threads and if we've
			 * already checked if there are similar threads, or if this is a
			 * poll, then pass over this
			 */

			if (Configuration.getInstance().isSuggestSimilarThreads() && (!confirmed) && (!isPoll)) {

				Search search = new Search();

				/*
				 * Need to escape special Lucene characters; also remove quotes
				 * and so on as they don't help here
				 */

				String queryString = questionTitle;
				queryString = queryString.replaceAll("\'", "");
				queryString = queryString.replaceAll("\\\"", "");
				queryString = Search.escapeQueryString(queryString);

				List<ThreadHit> threadHits = search.searchThreads(user, queryString, 0, 10, SortOrder.Relevance);
				List<ThreadHit> viewableThreadHits = new ArrayList<ThreadHit>();

				/* Take only the threads that this user can post on */

				for (ThreadHit threadHit : threadHits) {
					if (threadHit.canBePostedOnBy(user)) {
						viewableThreadHits.add(threadHit);
					}
				}

				if (viewableThreadHits.size() > 0) {

					/*
					 * Forward to chooser page, with data intact; otherwise,
					 * just post the thread.
					 */

					questionTitle = questionTitle.replace("\"", "&quot;");
					questionText = questionText.replace("\"", "&quot;");

					request.setAttribute("questionTitle", questionTitle);
					request.setAttribute("sKey", sessionKey);
					request.setAttribute("questionText", questionText);
					request.setAttribute("targetBoardId", targetBoardId);
					request.setAttribute("threadHits", viewableThreadHits);
					request.setAttribute("adminId", adminId);

					RequestDispatcher dispatcher = request.getRequestDispatcher("/Pages/choose-similar-thread.jsp");
					dispatcher.forward(request, response);
					return;

				} else {
					newThread = true;
				}
			}

		} catch (SQLException e) {
			throw new ServletException(e);
		} catch (ParseException e) {
		} catch (java.text.ParseException e) {
			throw new ServletException(e);
		}

		/*
		 * If it's a new thread (or it's a poll, which are always new threads,
		 * then post it as such; if not, tack it on the end of the existing
		 * thread that's been chosen
		 */

		if (newThread || isPoll || (!Configuration.getInstance().isSuggestSimilarThreads())) {
			NewQuestion newQuestion = new NewQuestion();
			newQuestion.doPost(request, response);
		} else {

			/* Tack the question text on as a response to the existing thread */

			try {
				/* Delegate to the new answer poster */

				NewAnswer newAnswer = new NewAnswer();
				newAnswer.setIgnoreXPosts(true);
				newAnswer.doPost(request, response);

			} catch (NumberFormatException e) {
				throw new ServletException(e);
			}

		}

	}

}
